#pragma once

#include <iostream>
#include <string>
#include <unistd.h>
#include <vector>
#include <sys/types.h>
#include <sys/wait.h>
#include "Task.hpp"

static const int process_num = 10; // 进程池进程数量
std::vector<task> tasks;           // 任务数组--不同编号代表不同的任务

struct channel
{
    int _fd;                   // 关联的文件描述符
    pid_t _worker_id;          // 对应的进程id
    std::string _process_name; // 匿名管道自定义名称--方便记录和打印

    // 构造函数
    channel(int fd, int worker_id, const std::string &process_name)
        : _fd(fd), _worker_id(worker_id), _process_name(process_name) {}
};

// 执行任务代码
void Work()
{
    while (true)
    {
        // 获取任务码
        int cmd_code = 0;
        ssize_t n = read(0, &cmd_code, sizeof(cmd_code));
        if (n == sizeof(cmd_code))
        {
            std::cout << "get a command " << cmd_code << std::endl;
            // 判断任务码是否正确，并执行任务
            if (cmd_code >= 0 && cmd_code < tasks.size())
            {
                tasks[cmd_code]();
            }
        }
        else if (n == 0)
        {
            std::cout << "stdin close" << std::endl;
            break;
        }
        else
        {
            std::cout << "read cmd_code fail" << std::endl;
            exit(-1);
        }
    }
}

// 初始化线程池
void InitProcessPool(std::vector<channel> *channels)
{
    for (int i = 0; i < process_num; i++)
    {
        // 创建匿名管道
        int pipefd[2];
        int n = pipe(pipefd);

        // 创建子进程
        pid_t id = fork();
        // 子进程
        if (id == 0)
        {
            // 关闭写端
            close(pipefd[1]);
            // 将标准输入重定向为pipefd[0]，不再是键盘文件取出数据，而是从pipefd[0]中取出数据
            dup2(pipefd[0], 0);
            // 关闭文件描述符pipefd[0]，并非关闭pipefd[0]文件，因为文件描述符有0还在指向该文件
            close(pipefd[0]);
            // 执行任务
            Work();
            // 进程退出
            std::cout << "process : " << getpid() << "quit;" << std::endl;
            exit(0);
        }
        // 关闭读端
        close(pipefd[0]);

        // 添加到channel字段
        std::string name = "process-" + std::to_string(i);
        channels->push_back(channel(pipefd[1], id, name));
    }
}

// 输入任务
void InputWork(const std::vector<channel> &channels)
{
    int which = 0;
    while (true)
    {
        // 选择任务
        int select = 0;
        std::cout << "please Enter@ ";
        std::cin >> select;

        if (select <= 0 || select >= 5)
            continue;
        // 生成任务码
        int cmd_code = select - 1;

        // 选择进程
        std::cout << "Leave this task to the "
                  << channels[which]._process_name << " process to complete " << std::endl;
        // 发送任务--向对应管道中写入
        write(channels[which]._fd, &cmd_code, sizeof(cmd_code));

        which++;
        which %= channels.size();
    }
}

// 关闭线程池
void QuitProcess(const std::vector<channel> &channels)
{
    //关闭所有管道文件描述符
    for(const auto& channel : channels)
        close(channel._fd);

    //等待所有子进程的退出
    for(const auto& channel : channels)
        waitpid(channel._worker_id, nullptr, 0);
}